/***************************************************************
*
* SSL_TEST.CPP
*
* SSL tests
***************************************************************/

#include <ap_comm.h>

#include <ds_list.h>
#include <ds_hash.h>
#include <ds_string.h>
#include <ds_smart_ptr.h>
#include <ps_sys.h>

/*
class A {
public:
   virtual void funcV (void)
   {
      int a;
      a = 1;
   }

   void funcNV(void)
   {
      int a;
      a = 1;
   }
};

class B : public A {
public:
   virtual void funcV (void)
   {
      int a;
      a = 1;
   }
};

class C {
   int QQQ;
public:
   int funcXXX (void)
   {
      int a;
      a = 1;
      return 0;
   }
};

void dsTest1 (void) 
{
   typedef void (A::* PMF)();
   typedef int  (C::* PMF_C)();
   PMF p;
   A a;
   B b;
   A *pA = (A*)new B;
   PMF_C t;

   p = (PMF)A::funcV;
   t = C::funcXXX;

   // p = (PMF)t;

   (pA->*p)();
   // (b.*p)();

   return;
}
*/


//
// TRUE - call code; FALSE - don't call code
//
BOOL sslCallScript (class base *pBase, psSECTION &psIn, psSECTION &psOut)
{
   return FALSE;
}

typedef void (base::* sslPMF_V_V) ();
typedef int  (base::* sslPMF_I_V) (void);
typedef void (base::* sslPMF_S_V) ();
typedef void (base::* sslPMF_E_V) ();
typedef int  (base::* sslPMF_I_E) (base *);
typedef void (base::* sslPMF_V_F) (float);
typedef float(base::* sslPMF_F_V) (void);

class sslFUNCTOR {
   sslFUNCTOR();

protected:
   dsSTRING    name;
   base       *pBase;
public:
   sslFUNCTOR(char *_name, base *_pBase);

   dsSTRING&   GetName (void) { return name; }

   virtual void Execute (psSECTION &psIn, psSECTION &psOut) = 0;
};

class sslFUNCTOR_I_V : public sslFUNCTOR {
   sslPMF_I_V pmf;
public:
   sslFUNCTOR_I_V(char *_name, base *_pBase, sslPMF_I_V _pmf) : sslFUNCTOR(_name, _pBase), pmf(_pmf) {}

   int operator()  (void)     
   { 
      // call script
      psSECTION   psIn, psOut;
      int         t;
      if (sslCallScript(pBase, psIn, psOut)) {
         psOut->GetInt("1", &t);
         return t;
      }
      return CallCode(); 
   }

   int CallCode (void) { return (pBase->*pmf)(); }

   void Execute (psSECTION &psIn, psSECTION &psOut)
   {
      int t;
      // psDATA

      t = CallCode();
      // psOut->AddKey("out", t);
      return ;
   }
};

class sslFUNCTOR_F_V : public sslFUNCTOR {
   sslPMF_F_V pmf;
public:
   sslFUNCTOR_F_V(char *_name, base *_pBase, sslPMF_F_V _pmf) : sslFUNCTOR(_name, _pBase), pmf(_pmf) {}

   float operator()  (void)     
   { 
      // call script
      psSECTION   psIn, psOut;
      float       t;
      if (sslCallScript(pBase, psIn, psOut)) {
         psOut->GetFloat("1", &t);
         return t;
      }
      return CallCode(); 
   }

   float CallCode (void) { return (pBase->*pmf)(); }

   void Execute (psSECTION &psIn, psSECTION &psOut)
   {
      float t;
      // psDATA

      t = CallCode();
      // psOut->AddKey("out", t);
      return ;
   }
};

class sslFUNCTOR_V_F : public sslFUNCTOR {
   sslPMF_V_F pmf;
public:
   sslFUNCTOR_V_F(char *_name, base *_pBase, sslPMF_V_F _pmf) : sslFUNCTOR(_name, _pBase), pmf(_pmf) {}

   void operator()  (float t)     
   { 
      // call script
      psSECTION   psIn, psOut;
      if (sslCallScript(pBase, psIn, psOut)) {
         return ;
      }
      CallCode(t); 
      return;
   }

   void CallCode (float t) { (pBase->*pmf)(t); return; }

   void Execute (psSECTION &psIn, psSECTION &psOut)
   {
      float t;

      psOut->GetFloat("in", &t);
      CallCode(t);
      return ;
   }
};

class sslFUNCTOR_I_E : public sslFUNCTOR {
   sslPMF_I_E pmf;
public:
   sslFUNCTOR_I_E(char *_name, base *_pBase, sslPMF_I_E _pmf) : sslFUNCTOR(_name, _pBase), pmf(_pmf) {}

   int operator ()  (base *pB)     
   { 
      // call script
      psSECTION   psIn, psOut;
      int         t;
      if (sslCallScript(pBase, psIn, psOut)) {
         psOut->GetInt("1", &t);
         return t;
      }
      return CallCode(pB); 
   }

   int CallCode (base *pB) { return (pBase->*pmf)(pB); }

   void Execute (psSECTION &psIn, psSECTION &psOut)
   {
      char  buf[AP_MAXNAME];
      int   t;
      base *pB;
      // psDATA

      psIn->GetString("1", buf, AP_MAXNAME);
      pB = NULL; // <<< FindEntity(buf);

      t = CallCode(pB);
      // psOut->AddKey("out", );
      return ;
   }
};

class sslIFACE {
   dsVECTOR<sslFUNCTOR*>   functorList;
public:
   void AddFunctor   (sslFUNCTOR *pFunctor) { functorList.PushBack(pFunctor); }
   void Execute      (char *nameFunc, psSECTION &psIn, psSECTION &psOut);
};

void sslIFACE::Execute (char *nameFunc, psSECTION &psIn, psSECTION &psOut) 
{
   sslFUNCTOR *func;
   int         i;

   for (i = 0; i < functorList.Length(); i++) {
      if (functorList[i]->GetName() == nameFunc) {
         break;
      }
   }
   if (i == functorList.Length()) {
      // cannot find named function
      ASSERT(FALSE);
      return;
   }

   func = functorList[i]; // find func

   func->Execute(psIn, psOut);
   return;
};

class base {
public:
   sslIFACE sslIFace;
};

#define SSL_DECL_FUNCTOR(func, type) \
   sslFUNCTOR_##type   func
#define SSL_INIT_FUNCTOR(func, type) \
   func(#func, this, (sslPMF_##type)func##Impl)

#define SSL_DECL_VAR_FLOAT(var) \
   sslFUNCTOR_F_V   SSL_functorGet##var; \
   sslFUNCTOR_V_F   SSL_functorSet##var

#define SSL_INIT_VAR(var, getvar, setvar) \
   SSL_functorGet##var(#getvar, this, getvar) , \
   SSL_functorSet##var(#setvar, this, setvar)

#define SSL_INIT_VAR_FLOAT(var) \
   SSL_INIT_VAR(var, (sslPMF_F_V)Get##var, (sslPMF_V_F)Set##var)

class A : public base {
protected:
   virtual BOOL IsReadyOpenImpl (void)
   {
      int a;
      a = 1;
      return a;
   }
   virtual BOOL ActivateImpl    (base *pBase)
   {
      int a;
      a = 1;
      return a;
   }
   float    health;

   float    GetHealth (void)           { return health; }
   void     SetHealth (float _health)  { health = _health; }
public:
   SSL_DECL_FUNCTOR(IsReadyOpen, I_V);
   SSL_DECL_FUNCTOR(Activate,    I_E);
   SSL_DECL_VAR_FLOAT(Health);

   A () : SSL_INIT_FUNCTOR(IsReadyOpen, I_V), SSL_INIT_FUNCTOR(Activate, I_E),
          SSL_INIT_VAR_FLOAT(Health) {};
};

class B : public A {
protected:
   virtual BOOL IsReadyOpenImpl (void)
   {
      int a;
      a = 1;
      return a;
   }
};

sslFUNCTOR::sslFUNCTOR(char *_name, base *_pBase) : name(_name), pBase(_pBase)
{
   pBase->sslIFace.AddFunctor(this);
   return;
}

void dsTest1 (void)
{
   base  bs;
   A     a;
   B     b;
   psSECTION  psIn;
   psSECTION  psOut;

   a.IsReadyOpen();
   a.Activate(&bs);

   a.sslIFace.Execute("IsReadyOpen", psIn, psOut);
   a.sslIFace.Execute("Activate", psIn, psOut);

   b.IsReadyOpen();
   b.sslIFace.Execute("IsReadyOpen", psIn, psOut);

   b.sslIFace.Execute("GetHealth", psIn, psOut);

   return;
}

/*
template <typename PMF>
class sslFUNCTOR {
public:
   dsSTRING    str;
   PMF         pmf;
   base       *pBase;

   int operator()  (void)     
   { 
      // call script
      psSECTION   psIn, psOut;
      int         t;
      if (sslCallScript(psIn, psOut)) {
         psOut->GetInt("1", &t);
         return t;
      }
      return CallCode(); 
   }
   int CallCode (void) { return (pBase->*pmf)(); }

   int operator()  (base *pB) 
   { 
      // call script
      psSECTION   psIn, psOut;
      int         t;
      if (sslCallScript(psIn, psOut)) {
         psOut->GetInt("1", &t);
         return;
      }
      return (pBase->*pmf)(pB); 
   }
   int CallCode (base *pB) { return (pBase->*pmf)(pB); }

   void Execute (psSECTION &psIn, psSECTION &psOut);
};

template<>
class sslFUNCTOR<sslPMF_I_V> {
public:
   void Execute (psSECTION &psIn, psSECTION &psOut)
   {
      int t;
      // psDATA

      t = CallCode();
      // psOut->AddKey("out", t);
      return ;
   }
};

template <>
class sslFUNCTOR<sslPMF_I_E> {
   void Execute (psSECTION &psIn, psSECTION &psOut)
   {
      char  buf[AP_MAXNAME];
      int   t;
      base *pB;
      // psDATA

      psIn->GetString("1", buf, AP_MAXNAME);
      pB = NULL; // <<< FindEntity(buf);

      t = CallCode(pB);
      // psOut->AddKey("out", );
      return ;
   }
};
*/

//
// End-of-file SSL_TEST.CPP
//
